/*
** Dump.c
** handle dump window and associated menu.
*/

#include "dis6502.h"

static WORD wSpriteMode = 13;
static WORD wSpriteNbBytes = 1;
static BOOL bLoHiEnterLoByte;
static WORD wLoHiKnownByte;
static WORD wLoHiNewByte;

static WORD wFindSegment = NO_DUMP;
static WORD wFindOffset = 0;
static char szFindString[256];
static int nFindLength = 0;
static BOOL bFindWhole = TRUE;

static void SelectMode(HWND hDlg, WORD wMode)
{
WORD wNbBytesPerLine;

     wSpriteMode = wMode;
     SendDlgItemMessage(hDlg, IDC_GRAPHIC, WM_SPRITE_SET_MODE, wMode, FALSE);
     wNbBytesPerLine = (WORD) SendDlgItemMessage(hDlg, IDC_GRAPHIC, WM_SPRITE_GET_INFO, SPRITE_NBBYTESPERLINE, 0);
     if (wSpriteNbBytes > wNbBytesPerLine)
          wSpriteNbBytes = wNbBytesPerLine;
     SendDlgItemMessage(hDlg, IDC_GRAPHIC, WM_SPRITE_SET_NBBYTES, wSpriteNbBytes, FALSE);
     SetDlgItemInt(hDlg, IDC_SPRITEWIDTH, wSpriteNbBytes, FALSE);
}

static void SelectGoto(HWND hDlg)
{
WORD wIndex, wEnd;
WORD wFirstLineSelected;
WORD wLastLineSelected;
WORD wFirstColSelected;
WORD wLastColSelected;

     if (wDumpBeginLine != DUMP_NO_SELECTION)
          {
          if (wDumpBeginLine > wDumpEndLine)
               {
               wFirstLineSelected = wDumpEndLine;
               wLastLineSelected = wDumpBeginLine;
               wFirstColSelected = wDumpEndCol;
               wLastColSelected = wDumpBeginCol;
               }
          else if (wDumpBeginLine < wDumpEndLine)
               {
               wFirstLineSelected = wDumpBeginLine;
               wLastLineSelected = wDumpEndLine;
               wFirstColSelected = wDumpBeginCol;
               wLastColSelected = wDumpEndCol;
               }
          else {
               wFirstLineSelected = wLastLineSelected = wDumpBeginLine;
               if (wDumpBeginCol > wDumpEndCol)
                    {
                    wFirstColSelected = wDumpEndCol;
                    wLastColSelected = wDumpBeginCol;
                    }
               else {
                    wFirstColSelected = wDumpBeginCol;
                    wLastColSelected = wDumpEndCol;
                    }
               }
          wIndex = (wFirstLineSelected * 8) + wFirstColSelected;
          wEnd = (wLastLineSelected * 8) + wLastColSelected;
          }
     else {
          wIndex = 0;
          wEnd = SPRITE_NO_SELECTION;
          }
     SendDlgItemMessage(hDlg, IDC_GRAPHIC, WM_SPRITE_SET_INDEX, wIndex, FALSE);
     SendDlgItemMessage(hDlg, IDC_GRAPHIC, WM_SPRITE_SET_SELECTION, wEnd, FALSE);
     if ((wEnd != SPRITE_NO_SELECTION) && (wEnd >= wIndex))
          wsprintf(szErr, "$%04X - $%04X", Segment[wDumpSegment].wBegin + wIndex, Segment[wDumpSegment].wBegin + wEnd);
     else wsprintf(szErr, "$%04X", Segment[wDumpSegment].wBegin + wIndex);
     SetDlgItemText(hDlg, IDC_ADDRESSSTART, szErr);
}

static void SelectInit(HWND hDlg)
{
RECT rc, rcDlg;
int iAdjustWidth, iAdjustHeight;
int iTopClient, iLeftClient;
char szGraphic[80];
DWORD dwIndex;
WORD wLastIndex;

     if (LoadString(hInst, IDS_ANTIC_8, szGraphic, sizeof(szGraphic)) == 0)
          strcpy(szGraphic, "ANTIC 8 (40x24x4)");
     SendMessage(GetDlgItem(hDlg, IDC_GRAPHICCOMBO), CB_ADDSTRING, 0, (LPARAM) (LPCSTR) szGraphic);
     if (LoadString(hInst, IDS_ANTIC_9, szGraphic, sizeof(szGraphic)) == 0)
          strcpy(szGraphic, "ANTIC 9 (80x48x2)");
     SendMessage(GetDlgItem(hDlg, IDC_GRAPHICCOMBO), CB_ADDSTRING, 0, (LPARAM) (LPCSTR) szGraphic);
     if (LoadString(hInst, IDS_ANTIC_A, szGraphic, sizeof(szGraphic)) == 0)
          strcpy(szGraphic, "ANTIC A (80x48x4)");
     SendMessage(GetDlgItem(hDlg, IDC_GRAPHICCOMBO), CB_ADDSTRING, 0, (LPARAM) (LPCSTR) szGraphic);
     if (LoadString(hInst, IDS_ANTIC_B, szGraphic, sizeof(szGraphic)) == 0)
          strcpy(szGraphic, "ANTIC B (160x96x2)");
     SendMessage(GetDlgItem(hDlg, IDC_GRAPHICCOMBO), CB_ADDSTRING, 0, (LPARAM) (LPCSTR) szGraphic);
     if (LoadString(hInst, IDS_ANTIC_C, szGraphic, sizeof(szGraphic)) == 0)
          strcpy(szGraphic, "ANTIC C (160x192x2)");
     SendMessage(GetDlgItem(hDlg, IDC_GRAPHICCOMBO), CB_ADDSTRING, 0, (LPARAM) (LPCSTR) szGraphic);
     if (LoadString(hInst, IDS_ANTIC_D, szGraphic, sizeof(szGraphic)) == 0)
          strcpy(szGraphic, "ANTIC D (160x96x4)");
     dwIndex = SendMessage(GetDlgItem(hDlg, IDC_GRAPHICCOMBO), CB_ADDSTRING, 0, (LPARAM) (LPCSTR) szGraphic);
     if (LoadString(hInst, IDS_ANTIC_E, szGraphic, sizeof(szGraphic)) == 0)
          strcpy(szGraphic, "ANTIC E (160x192x4)");
     SendMessage(GetDlgItem(hDlg, IDC_GRAPHICCOMBO), CB_ADDSTRING, 0, (LPARAM) (LPCSTR) szGraphic);
     if (LoadString(hInst, IDS_ANTIC_F, szGraphic, sizeof(szGraphic)) == 0)
          strcpy(szGraphic, "ANTIC F (320x192x1)");
     SendMessage(GetDlgItem(hDlg, IDC_GRAPHICCOMBO), CB_ADDSTRING, 0, (LPARAM) (LPCSTR) szGraphic);

     GetClientRect(GetDlgItem(hDlg, IDC_GRAPHIC), &rc);
     iAdjustWidth = 320 - rc.right + GetSystemMetrics(SM_CXVSCROLL);
     iAdjustHeight = 192 - rc.bottom;
     GetWindowRect(hDlg, &rcDlg);
     GetClientRect(hDlg, &rc);
     ClientToScreen(hDlg, (POINT *) &rc);
     iLeftClient = rc.left;
     iTopClient = rc.top;
     MoveWindow(hDlg, rcDlg.left, rcDlg.top, rcDlg.right - rcDlg.left + iAdjustWidth + 1, rcDlg.bottom - rcDlg.top + iAdjustHeight + 1, FALSE);
     GetWindowRect(GetDlgItem(hDlg, IDC_GRAPHIC), &rc);
     MoveWindow(GetDlgItem(hDlg, IDC_GRAPHIC), rc.left - iLeftClient, rc.top - iTopClient, rc.right - rc.left + iAdjustWidth + 1, rc.bottom - rc.top + iAdjustHeight + 1, FALSE);
     GetWindowRect(GetDlgItem(hDlg, IDC_ADDRESSTEXT), &rc);
     MoveWindow(GetDlgItem(hDlg, IDC_ADDRESSTEXT), rc.left - iLeftClient, rc.top - iTopClient + iAdjustHeight, rc.right - rc.left + 1, rc.bottom - rc.top + 1, FALSE);
     GetWindowRect(GetDlgItem(hDlg, IDC_ADDRESSSTART), &rc);
     MoveWindow(GetDlgItem(hDlg, IDC_ADDRESSSTART), rc.left - iLeftClient, rc.top - iTopClient + iAdjustHeight, rc.right - rc.left + 1, rc.bottom - rc.top + 1, FALSE);
     GetWindowRect(GetDlgItem(hDlg, IDC_SPRITETEXT), &rc);
     MoveWindow(GetDlgItem(hDlg, IDC_SPRITETEXT), rc.left - iLeftClient + iAdjustWidth + 1, rc.top - iTopClient + iAdjustHeight, rc.right - rc.left + 1, rc.bottom - rc.top + 1, FALSE);
     GetWindowRect(GetDlgItem(hDlg, IDC_SPRITEWIDTH), &rc);
     MoveWindow(GetDlgItem(hDlg, IDC_SPRITEWIDTH), rc.left - iLeftClient + iAdjustWidth + 1, rc.top - iTopClient + iAdjustHeight, rc.right - rc.left + 1, rc.bottom - rc.top + 1, FALSE);
     GetWindowRect(GetDlgItem(hDlg, IDC_GRAPHICTEXT), &rc);
     MoveWindow(GetDlgItem(hDlg, IDC_GRAPHICTEXT), rc.left - iLeftClient, rc.top - iTopClient + iAdjustHeight, rc.right - rc.left + 1, rc.bottom - rc.top + 1, FALSE);
     GetWindowRect(GetDlgItem(hDlg, IDC_GRAPHICCOMBO), &rc);
     MoveWindow(GetDlgItem(hDlg, IDC_GRAPHICCOMBO), rc.left - iLeftClient, rc.top - iTopClient + iAdjustHeight, rc.right - rc.left + iAdjustWidth + 1, (rc.bottom - rc.top + 1) * 8, FALSE);
     GetWindowRect(GetDlgItem(hDlg, IDOK), &rc);
     MoveWindow(GetDlgItem(hDlg, IDOK), rc.left - iLeftClient + (iAdjustWidth / 2), rc.top - iTopClient + iAdjustHeight, rc.right - rc.left + 1, rc.bottom - rc.top + 1, FALSE);
     GetWindowRect(GetDlgItem(hDlg, IDCANCEL), &rc);
     MoveWindow(GetDlgItem(hDlg, IDCANCEL), rc.left - iLeftClient + (iAdjustWidth / 2), rc.top - iTopClient + iAdjustHeight, rc.right - rc.left + 1, rc.bottom - rc.top + 1, FALSE);

     wLastIndex = Segment[wDumpSegment].wEnd - Segment[wDumpSegment].wBegin;
     SendDlgItemMessage(hDlg, IDC_GRAPHIC, WM_SPRITE_SET_BUFFER, wLastIndex, (LPARAM) (DWORD) Segment[wDumpSegment].lpDump);
     SelectGoto(hDlg);
     SelectMode(hDlg, wSpriteMode);
     SendMessage(GetDlgItem(hDlg, IDC_GRAPHICCOMBO), CB_SETCURSEL, (WPARAM) wSpriteMode - 8, 0);
}

BOOL __export CALLBACK SelectSpritesProc(HWND hDlg, UINT message, WORD wParam, LONG lParam)
{
DWORD dwIndex;
WORD wIndex;
WORD wBegin, wEnd;

     switch (message)
          {
          case WM_INITDIALOG:
               SelectInit(hDlg);
               return TRUE;

          case WM_COMMAND:
               switch (wParam)
                    {
                    case IDOK:
                         wIndex = (WORD) SendDlgItemMessage(hDlg, IDC_GRAPHIC, WM_SPRITE_GET_INDEX, 0, 0);
                         wEnd = (WORD) SendDlgItemMessage(hDlg, IDC_GRAPHIC, WM_SPRITE_GET_SELECTION, 0, 0);
                         if ((wEnd != SPRITE_NO_SELECTION) && (wEnd >= wIndex))
                              {
                              wBegin = wIndex;
                              wDumpBeginLine = wIndex / 8;
                              wDumpBeginCol = wIndex & 0x07;
                              wDumpEndLine = wEnd / 8;
                              wDumpEndCol = wEnd & 0x07;
                              }
                         else wBegin = wEnd = DUMP_NO_SELECTION;
                         SendDlgItemMessage(GetParent(hDlg), ID_DUMP, WM_DUMP_SET_BEGIN_SELECTION, wBegin, FALSE);
                         SendDlgItemMessage(GetParent(hDlg), ID_DUMP, WM_DUMP_SET_END_SELECTION, wEnd, FALSE);
                         SendDlgItemMessage(GetParent(hDlg), ID_DUMP, WM_DUMP_SEEK_SELECTION, 0, 0);
                         wSpriteMode = (WORD) SendDlgItemMessage(hDlg, IDC_GRAPHIC, WM_SPRITE_GET_MODE, 0, 0) + 8;
                         wSpriteNbBytes = (WORD) SendDlgItemMessage(hDlg, IDC_GRAPHIC, WM_SPRITE_GET_NBBYTES, 0, 0);
                         EndDialog(hDlg, TRUE);
                         return TRUE;

                    case IDCANCEL:
                         EndDialog(hDlg, FALSE);
                         return TRUE;

                    case IDC_GRAPHICCOMBO:
                         switch (HIWORD(lParam))
                              {
                              case CBN_SELCHANGE:
                                   dwIndex = SendDlgItemMessage(hDlg, IDC_GRAPHICCOMBO, CB_GETCURSEL, 0, 0);
                                   if (dwIndex != LB_ERR)
                                        {
                                        SelectMode(hDlg, ((WORD) dwIndex) + 8);
                                        SendDlgItemMessage(hDlg, IDC_GRAPHIC, WM_SPRITE_REFRESH, 0, 0);
                                        }
                                   return TRUE;
                              }
                         break;

                    case IDC_GRAPHIC:
                         switch (HIWORD(lParam))
                              {
                              case SPRITE_INDEX_CHANGED:
                              case SPRITE_SELECTION_CHANGED:
                                   wIndex = (WORD) SendDlgItemMessage(hDlg, IDC_GRAPHIC, WM_SPRITE_GET_INDEX, 0, 0);
                                   wEnd = (WORD) SendDlgItemMessage(hDlg, IDC_GRAPHIC, WM_SPRITE_GET_SELECTION, 0, 0);
                                   if ((wEnd != SPRITE_NO_SELECTION) && (wEnd >= wIndex))
                                        wsprintf(szErr, "$%04X - $%04X", Segment[wDumpSegment].wBegin + wIndex, Segment[wDumpSegment].wBegin + wEnd);
                                   else wsprintf(szErr, "$%04X", Segment[wDumpSegment].wBegin + wIndex);
                                   SetDlgItemText(hDlg, IDC_ADDRESSSTART, szErr);
                                   return TRUE;

                              case SPRITE_NBBYTES_CHANGED:
                                   wIndex = (WORD) SendDlgItemMessage(hDlg, IDC_GRAPHIC, WM_SPRITE_GET_NBBYTES, 0, 0);
                                   SetDlgItemInt(hDlg, IDC_SPRITEWIDTH, wIndex, FALSE);
                                   return TRUE;

                                   return TRUE;
                              }
                         break;
                    }
               break;

          case WM_CTLCOLOR:

               /*
               ** change background color to gray.
               */
               if (HIWORD(lParam) == CTLCOLOR_STATIC || HIWORD(lParam) == CTLCOLOR_BTN || HIWORD(lParam) == CTLCOLOR_DLG)
                    {
                    SetBkColor((HDC) wParam, RGB(192, 192, 192));
                    return (BOOL) GetStockObject(LTGRAY_BRUSH);
                    }
               return FALSE;
          }
     return FALSE;
}

void DumpRegister(HANDLE hInstance)
{
     /*
     ** init variables
     */
     wDumpSegment = NO_DUMP;
     wDumpBeginLine = wDumpEndLine = DUMP_NO_SELECTION;
     DumpInit(hInstance);
     SpriteInit(hInstance);

     /*
     ** create drop-down menu opened on right button click.
     */
     hDumpMenuPopup = CreatePopupMenu();
     AppendMenu(hDumpMenuPopup, MF_SEPARATOR, (UINT) 0, "");
     AppendMenu(hDumpMenuPopup, MF_ENABLED | MF_STRING | (bConfigDumpInternal ? MF_CHECKED : MF_UNCHECKED), IDM_DUMP_DISPLAY, "Screen &Display");
     AppendMenu(hDumpMenuPopup, MF_ENABLED | MF_STRING | (bConfigNoDisassembly ? MF_CHECKED : MF_UNCHECKED), IDM_DUMP_NO_DIS, "N&o Disassembly");
     AppendMenu(hDumpMenuPopup, MF_SEPARATOR, (UINT) 0, "");
     AppendMenu(hDumpMenuPopup, MF_ENABLED | MF_STRING, IDM_DUMP_FIND_SPRITES, "Select S&prites...");
     AppendMenu(hDumpMenuPopup, MF_SEPARATOR, (UINT) 0, "");
     AppendMenu(hDumpMenuPopup, MF_ENABLED | MF_STRING, IDM_DUMP_SELECTALL, "&Select all");
     AppendMenu(hDumpMenuPopup, MF_SEPARATOR, (UINT) 0, "");
     AppendMenu(hDumpMenuPopup, MF_ENABLED | MF_STRING, IDM_DUMP_FIND, "&Find...");
     AppendMenu(hDumpMenuPopup, MF_ENABLED | MF_STRING, IDM_DUMP_FIND_NEXT, "Find &next\tF3");

     /*
     ** create a sub-menu for type of bytes.
     */
     hDumpSubMenuPopup = CreatePopupMenu();
     AppendMenu(hDumpSubMenuPopup, MF_ENABLED | MF_STRING, IDM_DUMP_TYPE_CODE, "&Code");
     AppendMenu(hDumpSubMenuPopup, MF_ENABLED | MF_STRING, IDM_DUMP_TYPE_LOBYTE, "Code with L&ow Byte");
     AppendMenu(hDumpSubMenuPopup, MF_ENABLED | MF_STRING, IDM_DUMP_TYPE_HIBYTE, "Code with H&igh Byte");
     AppendMenu(hDumpSubMenuPopup, MF_ENABLED | MF_STRING, IDM_DUMP_TYPE_BYTE, "&Byte");
     AppendMenu(hDumpSubMenuPopup, MF_ENABLED | MF_STRING, IDM_DUMP_TYPE_WORD, "&Word");
     AppendMenu(hDumpSubMenuPopup, MF_ENABLED | MF_STRING, IDM_DUMP_TYPE_LABEL, "&Label");
     AppendMenu(hDumpSubMenuPopup, MF_ENABLED | MF_STRING, IDM_DUMP_TYPE_STRING, "&String");
     AppendMenu(hDumpSubMenuPopup, MF_ENABLED | MF_STRING, IDM_DUMP_TYPE_SBYTE, "Screen B&yte");
     AppendMenu(hDumpSubMenuPopup, MF_ENABLED | MF_STRING, IDM_DUMP_TYPE_DLIST, "&Display List");
     AppendMenu(hDumpSubMenuPopup, MF_ENABLED | MF_STRING, IDM_DUMP_TYPE_STORE, "D&ata Store");
     InsertMenu(hDumpMenuPopup, 0, MF_POPUP | MF_BYPOSITION, (WORD) hDumpSubMenuPopup, "&Type");
}

void DumpTerm(void)
{
     if (hDumpMenuPopup)
          DestroyMenu(hDumpMenuPopup);
}

void DumpChangeSegment(HWND hWnd)
{
WORD wSize;

     wSize = Segment[wDumpSegment].wEnd - Segment[wDumpSegment].wBegin + 1;
     SendDlgItemMessage(hWnd, ID_DUMP, WM_DUMP_SET_BUFFER, wSize, (LPARAM) (DWORD) Segment[wDumpSegment].lpDump);
     SendDlgItemMessage(hWnd, ID_DUMP, WM_DUMP_SET_TYPE_BUFFER, Segment[wDumpSegment].wBegin, (LPARAM) (DWORD) Segment[wDumpSegment].lpType);
     SendDlgItemMessage(hWnd, ID_DUMP, WM_DUMP_SET_SCROLL, 0, FALSE);
     SendDlgItemMessage(hWnd, ID_DUMP, WM_DUMP_SET_BEGIN_SELECTION, DUMP_NO_SELECTION, FALSE);
     SendDlgItemMessage(hWnd, ID_DUMP, WM_DUMP_SET_END_SELECTION, DUMP_NO_SELECTION, FALSE);
     InvalidateRect(GetDlgItem(hWnd, ID_DUMP), NULL, TRUE);
}

void DumpDrawMenu(HWND hWnd)
{
POINT pt;
WORD wMenuId;

     if ((wDumpSegment == NO_DUMP) || (! hDumpMenuPopup))
          return;
     GetCursorPos(&pt);
     CheckMenuItem(hDumpMenuPopup, IDM_DUMP_DISPLAY, MF_BYCOMMAND | (bConfigDumpInternal ? MF_CHECKED : MF_UNCHECKED));
     CheckMenuItem(hDumpMenuPopup, IDM_DUMP_NO_DIS, MF_BYCOMMAND | (bConfigNoDisassembly ? MF_CHECKED : MF_UNCHECKED));
     EnableMenuItem(hDumpMenuPopup, IDM_DUMP_SELECTALL, MF_BYCOMMAND | (wDumpSegment != NO_DUMP ? MF_ENABLED : MF_GRAYED));
     EnableMenuItem(hDumpMenuPopup, IDM_DUMP_FIND, MF_BYCOMMAND | (DumpCanFind(TRUE) ? MF_ENABLED : MF_GRAYED));
     EnableMenuItem(hDumpMenuPopup, IDM_DUMP_FIND_NEXT, MF_BYCOMMAND | (DumpCanFind(FALSE) ? MF_ENABLED : MF_GRAYED));
     for (wMenuId = IDM_DUMP_TYPE_CODE; wMenuId < IDM_DUMP_TYPE_CODE + DUMP_TYPE_NUMBER; wMenuId++)
          EnableMenuItem(hDumpMenuPopup, wMenuId, MF_BYCOMMAND | ((wDumpBeginLine != DUMP_NO_SELECTION) ? MF_ENABLED : MF_GRAYED));
     TrackPopupMenu(hDumpMenuPopup, TPM_LEFTALIGN, pt.x, pt.y, 0, hWnd, NULL);
}

void DumpSelChanged(HWND hWnd)
{
WORD wBegin;
WORD wEnd;
WORD wSize;

     wSize = Segment[wDumpSegment].wEnd - Segment[wDumpSegment].wBegin + 1;
     wBegin = (WORD) SendDlgItemMessage(hWnd, ID_DUMP, WM_DUMP_GET_BEGIN_SELECTION, 0, 0);
     wEnd = (WORD) SendDlgItemMessage(hWnd, ID_DUMP, WM_DUMP_GET_END_SELECTION, 0, 0);
     if (wBegin == DUMP_NO_SELECTION)
          wDumpBeginLine = wDumpBeginCol = wDumpEndLine = wDumpEndCol = DUMP_NO_SELECTION;
     else {
          if (wBegin >= wSize)
               wBegin = wSize - 1;
          if (wEnd >= wSize)
               wEnd = wSize - 1;
          wDumpBeginLine = wBegin / 8;
          wDumpBeginCol = wBegin & 0x07;
          wDumpEndLine = wEnd / 8;
          wDumpEndCol = wEnd & 0x07;
          }
}

void DumpSprites(HWND hWnd)
{
     DialogBox(hInst, "FINDSPRITES", hWnd, SelectSpritesProc);
}

void DumpDisassemble(HWND hWnd)
{
     DisResetCodeLines(hMainWnd);
     SendDlgItemMessage(hMainWnd, ID_DIS, WM_DIS_SET_LINENUM, Config.config10.bLineNumbering, FALSE);
     InvalidateRect(GetDlgItem(hMainWnd, ID_DIS), NULL, TRUE);
     LabelFreeCode();
     DisProcess(hInst, hWnd);
}

BOOL __export CALLBACK LoHiByteProc(HWND hDlg, UINT message, WORD wParam, LONG lParam)
{
static WORD wIdKnownByte;
static WORD wIdUnknownByte;

     switch (message)
          {
          case WM_INITDIALOG:
               if (bLoHiEnterLoByte)
                    {
                    wIdKnownByte = IDC_HIBYTE;
                    wIdUnknownByte = IDC_LOBYTE;
                    }
               else {
                    wIdKnownByte = IDC_LOBYTE;
                    wIdUnknownByte = IDC_HIBYTE;
                    }
               wsprintf(szErr, "%02X", wLoHiKnownByte);
               SetDlgItemText(hDlg, wIdKnownByte, szErr);
               EnableWindow(GetDlgItem(hDlg, wIdKnownByte), FALSE);
               SendDlgItemMessage(hDlg, wIdUnknownByte, EM_LIMITTEXT, 2, 0);
               EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
               return TRUE;

          case WM_COMMAND:
               switch (wParam)
                    {
                    case IDOK:
                         GetDlgItemText(hDlg, wIdUnknownByte, szErr, 3);
                         sscanf(szErr, "%2X", &wLoHiNewByte);
                         EndDialog(hDlg, TRUE);
                         return TRUE;

                    case IDCANCEL:
                         EndDialog(hDlg, FALSE);
                         return TRUE;

                    case IDC_LOBYTE:
                    case IDC_HIBYTE:
                         if (wParam == wIdUnknownByte)
                              if (HIWORD(lParam) == EN_CHANGE)
                                   EnableWindow(GetDlgItem(hDlg, IDOK), (BOOL) SendDlgItemMessage(hDlg, wIdUnknownByte, WM_GETTEXTLENGTH, 0, 0));
                         break;
                    }
               break;

          case WM_CTLCOLOR:

               /*
               ** change background color to gray.
               */
               if (HIWORD(lParam) == CTLCOLOR_STATIC || HIWORD(lParam) == CTLCOLOR_BTN || HIWORD(lParam) == CTLCOLOR_DLG)
                    {
                    SetBkColor((HDC) wParam, RGB(192, 192, 192));
                    return (BOOL) GetStockObject(LTGRAY_BRUSH);
                    }
               return FALSE;
          }
     return FALSE;
}

BOOL DumpAskByte(HWND hWnd, BYTE cByte, WORD wType, BOOL *bNewByte)
{
     wLoHiKnownByte = (WORD) cByte;
     if (wType == DUMP_TYPE_LOBYTE)
          bLoHiEnterLoByte = FALSE;
     else bLoHiEnterLoByte = TRUE;
     if (DialogBox(hInst, "LOHIBYTEBOX", hWnd, LoHiByteProc) == FALSE)
          return FALSE;
     *bNewByte = (BYTE) wLoHiNewByte;
     return TRUE;
}

void DumpSetType(HWND hWnd, WORD wType)
{
WORD wBegin;
WORD wEnd;
WORD wFirst;
WORD wSize;
BOOL cNewByte;

     if (wDumpSegment == NO_DUMP)
          return;
     if (wDumpBeginLine == DUMP_NO_SELECTION)
          return;
     if (Segment[wDumpSegment].lpType == NULL)
          return;
     wBegin = (wDumpBeginLine * 8) + wDumpBeginCol;
     wEnd = (wDumpEndLine * 8) + wDumpEndCol;
     if (wBegin > wEnd)
          {
          wFirst = wEnd;
          wSize = wBegin - wEnd + 1;
          }
     else {
          wFirst = wBegin;
          wSize = wEnd - wBegin + 1;
          }
     if ((wFirst + wSize) >= (Segment[wDumpSegment].wEnd - Segment[wDumpSegment].wBegin + 1))
          wSize = Segment[wDumpSegment].wEnd - Segment[wDumpSegment].wBegin + 1 - wFirst;
     if ((wType == DUMP_TYPE_LOBYTE) || (wType == DUMP_TYPE_HIBYTE))
          {
          if (wFirst == 0)
               {
               Error(hWnd, IDS_ERR_LOHI_FIRST, "LOBYTE/HIBYTE not allowed for first byte of segment !");
               return;
               }
          if (wSize != 1)
               {
               Error(hWnd, IDS_ERR_MULTI_LOHI, "LOBYTE/HIBYTE can not be applied on a multi-byte selection !");
               return;
               }
          if (DisIsImmediateMode(Segment[wDumpSegment].lpDump[wFirst - 1]) == FALSE)
               {
               Error(hWnd, IDS_ERR_BAD_MODE_FOR_LOHI, "LOBYTE/HIBYTE is relevant only for immediate operand !");
               return;
               }
          if (DumpAskByte(hWnd, Segment[wDumpSegment].lpDump[wFirst], wType, &cNewByte) == FALSE)
               return;
          Segment[wDumpSegment].lpType[wFirst - 1] = (BYTE) wType;
          Segment[wDumpSegment].lpType[wFirst] = cNewByte;
          }
     else {
          if (wFirst)
               {
               if ((Segment[wDumpSegment].lpType[wFirst - 1] == DUMP_TYPE_LOBYTE)
                || (Segment[wDumpSegment].lpType[wFirst - 1] == DUMP_TYPE_HIBYTE))
                    Segment[wDumpSegment].lpType[wFirst - 1] = DUMP_TYPE_CODE;
               if ((Segment[wDumpSegment].lpType[wFirst + wSize - 1] == DUMP_TYPE_LOBYTE)
                || (Segment[wDumpSegment].lpType[wFirst + wSize - 1] == DUMP_TYPE_HIBYTE)
                /*&& not at the end of buffer*/)
                    Segment[wDumpSegment].lpType[wFirst + wSize] = DUMP_TYPE_CODE;
               }
          memset(Segment[wDumpSegment].lpType + wFirst, wType, wSize);
          }
     SendDlgItemMessage(hWnd, ID_DUMP, WM_DUMP_REFRESH, 0, 0);
     if (! bConfigNoDisassembly)
          DumpDisassemble(hWnd);
}

void DumpReset(HWND hWnd)
{
     wDumpSegment = NO_DUMP;
     if (hWnd)
          {
          SendDlgItemMessage(hWnd, ID_DUMP, WM_DUMP_SET_BUFFER, 0, 0);
          SendDlgItemMessage(hWnd, ID_DUMP, WM_DUMP_SET_TYPE_BUFFER, 0, 0);
          InvalidateRect(GetDlgItem(hWnd, ID_DUMP), NULL, TRUE);
          }
}

void DumpSetInternal(HWND hWnd)
{
     bConfigDumpInternal = ! bConfigDumpInternal;
     SendDlgItemMessage(hWnd, ID_DUMP, WM_DUMP_SET_INTERNAL, bConfigDumpInternal, TRUE);
}

BOOL DumpFindString(HWND hWnd, char *szFindAscii, int nLength, BOOL bWholeFile)
{
     if (bWholeFile)
          wFindSegment = 0;
     else wFindSegment = wDumpSegment;
     wFindOffset = 0;
     memcpy(szFindString, szFindAscii, min(nLength, sizeof(szFindString)));
     nFindLength = nLength;
     bFindWhole = bWholeFile;
     return DumpFindNextString(hWnd);
}

static BOOL DumpSearchString(int nSeg)
{
WORD wIndex;
WORD wBegin, wEnd;
WORD wSize;

     wSize = Segment[nSeg].wEnd - Segment[nSeg].wBegin + 1;
     if (wSize >= (WORD) nFindLength)
          for (wIndex = wFindOffset; wIndex <= (wSize - (WORD) nFindLength); wIndex++)
               if (Segment[nSeg].lpDump[wIndex] == (unsigned char) szFindString[0])
                    if (memcmp(&Segment[nSeg].lpDump[wIndex], szFindString, nFindLength) == 0)
                         {
                         wEnd = wIndex + (WORD) (nFindLength - 1);
                         wBegin = wIndex;
                         wFindSegment = (WORD) nSeg;
                         wFindOffset = wIndex + 1;
                         if (wFindSegment != wDumpSegment)
                              {
                              SendMessage(hSegmentList, LB_SETCURSEL, wFindSegment, 0L);
                              SegmentSelect(wFindSegment);
                              }
                         wDumpBeginLine = wIndex / 8;
                         wDumpBeginCol = wIndex & 0x07;
                         wDumpEndLine = wEnd / 8;
                         wDumpEndCol = wEnd & 0x07;
                         SendDlgItemMessage(hMainWnd, ID_DUMP, WM_DUMP_SET_BEGIN_SELECTION, wBegin, FALSE);
                         SendDlgItemMessage(hMainWnd, ID_DUMP, WM_DUMP_SET_END_SELECTION, wEnd, FALSE);
                         SendDlgItemMessage(hMainWnd, ID_DUMP, WM_DUMP_SEEK_SELECTION, 0, 0);
                         return TRUE;
                         }
     return FALSE;
}

BOOL DumpFindNextString(HWND hWnd)
{
int nSeg;
char szRes[256];

     if (wFindSegment != NO_DUMP)
          {
          for (nSeg = wFindSegment; nSeg < MAX_SEGMENTS; nSeg++)
               {
               if (Segment[nSeg].lpDump)
                    if (DumpSearchString(nSeg))
                         return TRUE;
               if (bFindWhole == 0)
                    break;
               wFindOffset = 0;
               }
          }
     if (LoadString(hInst, IDS_STRING_NOT_FOUND, szRes, sizeof(szRes)) == 0)
          strcpy(szRes, "String not found !");
     MessageBox(hWnd, szRes, szTitleApp, MB_OK | MB_ICONEXCLAMATION);
     return FALSE;
}

BOOL DumpCanFind(BOOL bFirst)
{
     if (wDumpSegment == NO_DUMP)
          return FALSE;
     if ((bFirst == FALSE) && (nFindLength == 0))
          return FALSE;
     return TRUE;
}

void DumpGetFindParam(char *szFindAscii, int *nLength, BOOL *bWhole)
{
     *nLength = min(nFindLength, sizeof(szFindString));
     memcpy(szFindAscii, szFindString, *nLength);
     szFindAscii[*nLength] = 0;
     *bWhole = bFindWhole;
}

void DumpSelectAll(void)
{
WORD wBegin, wEnd;

     if (wDumpSegment == NO_DUMP)
          return;
     if (Segment[wDumpSegment].lpDump == NULL)
          return;
     wEnd = Segment[wDumpSegment].wEnd - Segment[wDumpSegment].wBegin;
     wBegin = 0;
     wDumpBeginLine = wBegin / 8;
     wDumpBeginCol = wBegin & 0x07;
     wDumpEndLine = wEnd / 8;
     wDumpEndCol = wEnd & 0x07;
     SendDlgItemMessage(hMainWnd, ID_DUMP, WM_DUMP_SET_BEGIN_SELECTION, wBegin, FALSE);
     SendDlgItemMessage(hMainWnd, ID_DUMP, WM_DUMP_SET_END_SELECTION, wEnd, FALSE);
     SendDlgItemMessage(hMainWnd, ID_DUMP, WM_DUMP_SEEK_SELECTION, 0, 0);
}
